package com.example.scaffold.organization.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.scaffold.common.bean.PageResult;
import com.example.scaffold.common.exception.BusinessException;
import com.example.scaffold.organization.bean.OrganizationDTO;
import com.example.scaffold.organization.bean.OrganizationEditParam;
import com.example.scaffold.organization.bean.OrganizationQueryParam;
import com.example.scaffold.organization.bean.OrganizationVO;
import com.example.scaffold.organization.converter.OrganizationConverter;
import com.example.scaffold.organization.entity.Organization;
import com.example.scaffold.organization.mapper.OrganizationMapper;
import com.example.scaffold.organization.service.OrganizationService;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.example.scaffold.common.constant.RedisKeyConstant.ORGANIZATION_INFO_KEY;

/**
 * 机构服务实现类
 * 遵循阿里手册：服务实现类命名规范，缓存处理规范，事务管理规范
 *
 * @author example
 */
@Service
@RequiredArgsConstructor
public class OrganizationServiceImpl extends ServiceImpl<OrganizationMapper, Organization> implements OrganizationService {
    private static final Logger log = LoggerFactory.getLogger(OrganizationServiceImpl.class);
    
    private final RedisTemplate<String, Object> redisTemplate;
    private final OrganizationMapper organizationMapper;
    private final OrganizationConverter organizationConverter;

    /**
     * 根据ID查询机构，使用缓存
     */
    @Override
    public OrganizationDTO getOrganizationById(Long id) {
        if (id == null || id <= 0) {
            log.warn("查询机构ID不合法:{}", id);
            throw new BusinessException("机构ID不合法");
        }
        
        // 先查询缓存
        String cacheKey = String.format(ORGANIZATION_INFO_KEY, id);
        OrganizationDTO organizationDTO = (OrganizationDTO) redisTemplate.opsForValue().get(cacheKey);
        if (organizationDTO != null) {
            log.info("从缓存获取机构信息，机构ID:{}", id);
            return organizationDTO;
        }
        
        // 缓存未命中，查询数据库
        Organization organization = getById(id);
        if (organization == null) {
            log.warn("机构不存在，机构ID:{}", id);
            throw new BusinessException("机构不存在");
        }
        
        // 转换为DTO并缓存
        organizationDTO = BeanUtil.copyProperties(organization, OrganizationDTO.class);
        redisTemplate.opsForValue().set(cacheKey, organizationDTO, 30, TimeUnit.MINUTES);
        log.info("查询数据库并缓存机构信息，机构ID:{}", id);
        
        return organizationDTO;
    }

    /**
     * 创建机构，事务管理
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createOrganization(OrganizationEditParam param) {
        // 检查机构名称是否已存在
        Organization existingOrg = organizationMapper.selectByName(param.getName());
        if (existingOrg != null) {
            log.warn("机构名称已存在:{}", param.getName());
            throw new BusinessException("机构名称已存在");
        }
        
        // 转换为实体
        Organization organization = BeanUtil.copyProperties(param, Organization.class);
        organization.setStatus(1); // 默认正常状态
        organization.setFlag(true); // 默认标记为true
        organization.setDeleted(0); // 未删除
        organization.setCreateTime(LocalDateTime.now());
        organization.setUpdateTime(LocalDateTime.now());
        
        // 保存机构
        save(organization);
        log.info("创建机构成功，机构ID:{}", organization.getId());
        
        return organization.getId();
    }

    /**
     * 更新机构，更新缓存
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrganization(Long id, OrganizationEditParam param) {
        Organization organization = getById(id);
        if (organization == null) {
            log.warn("更新机构不存在，机构ID:{}", id);
            throw new BusinessException("机构不存在");
        }
        
        // 检查机构名称是否已存在（排除当前机构）
        Organization existingOrg = organizationMapper.selectByName(param.getName());
        if (existingOrg != null && !existingOrg.getId().equals(id)) {
            log.warn("机构名称已存在:{}", param.getName());
            throw new BusinessException("机构名称已存在");
        }
        
        // 复制属性，忽略null值
        BeanUtil.copyProperties(param, organization, "id", "createTime", "creator");
        organization.setUpdateTime(LocalDateTime.now());
        
        // 更新数据库
        boolean result = updateById(organization);
        
        // 更新缓存
        if (result) {
            String cacheKey = String.format(ORGANIZATION_INFO_KEY, id);
            OrganizationDTO updatedDTO = BeanUtil.copyProperties(organization, OrganizationDTO.class);
            redisTemplate.opsForValue().set(cacheKey, updatedDTO, 30, TimeUnit.MINUTES);
            log.info("更新机构及缓存成功，机构ID:{}", id);
        }
        
        return result;
    }

    /**
     * 删除机构，删除缓存
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteOrganization(Long id) {
        // 逻辑删除
        boolean result = removeById(id);
        
        // 删除缓存
        if (result) {
            String cacheKey = String.format(ORGANIZATION_INFO_KEY, id);
            redisTemplate.delete(cacheKey);
            log.info("删除机构及缓存成功，机构ID:{}", id);
        }
        
        return result;
    }

    @Override
    public PageResult<OrganizationVO> listOrganization(OrganizationQueryParam param) {
        IPage<Organization> page = new Page<>(param.getPageNum(), param.getPageSize());
        
        // 构建查询条件
        LambdaQueryWrapper<Organization> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(param.getStatus() != null, Organization::getStatus, param.getStatus())
                   .eq(param.getParentId() != null, Organization::getParentId, param.getParentId())
                   .like(param.getName() != null, Organization::getName, param.getName())
                   .eq(Organization::getDeleted, 0)
                   .orderByDesc(Organization::getCreateTime);
        
        IPage<Organization> resultPage = organizationMapper.selectPage(page, queryWrapper);
        List<OrganizationVO> organizationVOs = resultPage.getRecords().stream()
                .map(organizationConverter::toVO)
                .collect(Collectors.toList());

        PageResult<OrganizationVO> pageResult = new PageResult<>();
        pageResult.setTotal(resultPage.getTotal());
        pageResult.setPages(resultPage.getPages());
        pageResult.setPageNum(param.getPageNum());
        pageResult.setPageSize(param.getPageSize());
        pageResult.setList(organizationVOs);
        return pageResult;
    }
}